home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / jcool01.zip / GEN_STRI.C < prev    next >
C/C++ Source or Header  |  1992-08-14  |  33KB  |  812 lines

  1. //
  2. // Copyright (C) 1991 Texas Instruments Incorporated.
  3. //
  4. // Permission is granted to any individual or institution to use, copy, modify,
  5. // and distribute this software, provided that this complete copyright and
  6. // permission notice is maintained, intact, in all copies and supporting
  7. // documentation.
  8. //
  9. // Texas Instruments Incorporated provides this software "as is" without
  10. // express or implied warranty.
  11. //
  12. //
  13. // Created: MBN 03/17/89 -- Initial design and implementation
  14. // Updated: MBN 04/06/89 -- Performance enhancement by changing several
  15. //                          methods and friends to inline, and addition
  16. //                          of two private friend functions.
  17. // Updated: LGO 06/03/89 -- Fix string growth algorithm.
  18. // Updated: MBN 06/06/89 -- Performance enhancement by making reference count
  19. //                          and memory check/adjustment inline, addition of a
  20. //                          resize method and a growth ratio data slot, and
  21. //                          change of constructors to set specific object size,
  22. //                          not class as a whole
  23. // Updated: DKM 06/23/89 -- To get around a bug in the Glockenspiel translator
  24. //                          we had to explicitly typecast arguments for calls
  25. //                          to the overloaded unix string functions, including
  26. //                          strchr, strrchr, strcpy, strcmp, strncmp, strtod,
  27. //                          and strtol.
  28. // Updated: MNF 06/27/89 -- Added the insert, remove, replace, yank, and
  29. //                          sub_string public member functions.
  30. // Updated: MBN 06/30/89 -- Updated to include support for regular expressions
  31. // Updated: DKM 07/07/89 -- To work around Xenix 31 char limit:
  32. //                          Shortened is_less_than        to is_lt
  33. //                                    is_greater_than     to is_gt
  34. //                                    is_less_or_equal    to is_le
  35. //                                    is_greater_or_equal to is_ge
  36. //                          Removed is_equal_or_less and is_greater_or_less
  37. // Updated: MBN 09/07/89 -- Added conditional exception handling
  38. // Updated: MBN 09/26/89 -- Fixed bug to set size when growth size ratio given
  39. // Updated: LGO 10/11/89 -- Removed operator>>
  40. // Updated: LGO 10/28/89 -- Removed is_lt, is_gt, is_le, is_ge, is_equal
  41. //                          and is_not_equal (use char* functions instead)
  42. // Updated: MBN 12/15/89 -- Sprinkled "const" qualifier all over the place!
  43. // Updated: MBN 01/02/90 -- Made find search for the first/next regexp match 
  44. // Updated: LGO 01/03/90 -- Avoid use of strncat
  45. // Updated: LGO 01/05/90 -- Partial re-write of most everything to simplify
  46. //                          and speed-up the code
  47. // Updated: MJF 03/12/90 -- Added group names to RAISE
  48. // Updated: MJF 05/21/90 -- Moved delete from grow_memory to validate
  49. // Updated: DLS 03/22/91 -- New lite version
  50. // Updated: JAM 08/14/92 -- removed DOS specifics, stdized #includes
  51. // Updated: JAM 08/14/92 -- added static alloc_size_s def and initialization
  52. //
  53. // This  file contains member and  friend function  implementation code for the
  54. // CoolGen_String class defined  in  the  Gen_String.h and Regexp.h header   files.
  55. // Where appropriate and  possible, interfaces to, and  us  of, existing system
  56. // functions   has been incorporated.  An overview    of the structure   of the
  57. // Edit_String class, along with a synopsis of each member and friend function,
  58. // can be found in the String.h header file.
  59. //
  60.  
  61. #ifndef GEN_STRINGH                // If class not defined
  62. #include <cool/Gen_String.h>        // Include class specification
  63. #endif
  64.  
  65. #include <ctype.h>        // Include character processing macros
  66.  
  67. // alloc_size_s -- Memory allocation growth size
  68. int CoolGen_String::alloc_size_s = MEM_BLK_SZ;    // Init allocation size
  69.  
  70. // update_ref_count -- Gives "this" it's own (unshared) copy of a string
  71. // Input:          None
  72. // Output:       None
  73.  
  74. void CoolGen_String::update_ref_count() {
  75.   this->p->ref_count--;             // Decrement reference count
  76.   this->p = new String_Layout;         // Allocate layout structure
  77.   this->p->ref_count = 1;         // One object at the moment
  78.   this->p->size = 0;             // No memory allocated yet
  79.   this->p->start = this->str;         // Pointer to start of string
  80. }
  81.  
  82.  
  83. // validate -- protected method called when a string is modified
  84. // Input:        before calling, set this->length to new length.
  85. //               dont_copy - set to TRUE If you don't want the old string
  86. //               copied on a grow, or ref-count copy
  87. // Output:       None
  88. void CoolGen_String::validate(Boolean dont_copy) {
  89.   if (this->p->ref_count > 1) {      // If sharing memory with another CoolGen_String
  90.     this->update_ref_count();      // decrement reference count and 
  91.     this->grow_memory(dont_copy); // allocate memory for own copy
  92.   }
  93.   else if (this->length >= this->p->size) { // If not long enough,
  94.     char* ostr = this->str;            // save old string to delete later
  95.     this->grow_memory(dont_copy);        // allocate memory,
  96.     if (ostr != NULL) delete ostr;        // and free old memory block
  97.   }
  98. }
  99.  
  100. // grow_memory -- Called when string isn't long enough, or to allocate memory
  101. //                after update_ref_count inside validate.
  102. // Input:         dont_copy - TRUE If you don't want the old string copied.
  103. // Output:      None
  104.  
  105. void CoolGen_String::grow_memory (Boolean dont_copy) {
  106.   char* old_chars = this->str;
  107.   long size = this->p->size;
  108.   if (this->length >= size) { // Called from validate just to allocate memory
  109.     if (this->growth_ratio != 0.0)     // If a growth ratio is set
  110.       size += long(size * this->growth_ratio);
  111.     else
  112.       size += this->alloc_size_s;    // Increment by allocation size
  113.     if (size < this->length)         // But if still not big enough
  114.       size = this->length+1;         // Grow to big enough size
  115.     this->p->size = size;
  116.   }
  117.   this->str = new char[size];         // Allocate memory for string
  118.   this->p->start = this->str;         // Pointer to start of string
  119.   if (old_chars != NULL) {
  120.     if (!dont_copy)
  121.       strcpy ((char *)this->str, old_chars);   // Copy initial string
  122.   }
  123.   else
  124.     *this->str = END_OF_STRING;
  125. }
  126.  
  127.  
  128. // CoolGen_String() -- Simple constructor for a CoolGen_String object. Memory is
  129. //                 allocated for the layout structure and char* pointers are
  130. //                 set to the "alloc_size_s" value.
  131. // Input:          None
  132. // Output:         CoolGen_String reference
  133.  
  134.  
  135. CoolGen_String::CoolGen_String () {        
  136.   this->growth_ratio = 0.0;        // Initialize growth ratio
  137.   this->str = new char[alloc_size_s];    // Allocate block of memory
  138.   this->length = 0;            // Zero characters in string
  139.   this->p = new String_Layout;        // Allocate layout structure
  140.   this->p->ref_count = 1;        // One String object at the moment
  141.   this->p->size = alloc_size_s;        // Size of allocated block 
  142.   this->p->start = str;            // Pointer to start of string 
  143.   *this->str = END_OF_STRING;        // END_OF_STRING terminate for safety
  144.   this->rgexp = NULL;            // No regular expression yet
  145. }
  146.  
  147.  
  148. // CoolGen_String(char) -- Constructor to initialize object with a char
  149. // Input:              character
  150. // Output:             CoolGen_String reference to new object
  151.  
  152. CoolGen_String::CoolGen_String (char c) {        
  153.   this->growth_ratio = 0.0;        // Initialize growth ratio
  154.   this->length = 1;            // Length of character is 1
  155.   this->str = new char[length+1];    // Allocate memory for string
  156.   this->p = new String_Layout;        // Allocate layout structure
  157.   this->p->ref_count = 1;        // One String object at the moment
  158.   this->p->size = this->length+1;    // Size of allocated block
  159.   this->p->start = this->str;        // Pointer to start of string
  160.   *this->str = c;            // Assign character
  161.   *(this->str+1) = END_OF_STRING;    // END_OF_STRING terminator for string
  162.   this->rgexp = NULL;            // No regular expression yet
  163. }
  164.  
  165.  
  166. // CoolGen_String(char*) -- Constructor to initialize object with a char*.
  167. // Input:               char* pointer
  168. // Output:              CoolGen_String reference to new object
  169.  
  170. CoolGen_String::CoolGen_String (const char* c) {        
  171.   this->growth_ratio = 0.0;        // Initialize growth ratio
  172.   this->length = strlen (c);        // Determine length of character string
  173.   this->str = new char[length+1];    // Allocate memory for string
  174.   this->p = new String_Layout;        // Allocate layout structure
  175.   this->p->ref_count = 1;        // One String object at the moment
  176.   this->p->size = this->length+1;    // Size of allocated block
  177.   this->p->start = this->str;        // Pointer to start of string
  178.   strcpy ((char *)this->str, c);    // Copy characters
  179.   this->rgexp = NULL;            // No regular expression yet
  180. }
  181.  
  182.  
  183. // CoolGen_String(CoolGen_String&) -- Constructor to initialize object to CoolGen_String
  184. //                            Note that this involves use of delayed copy via 
  185. //                            the reference count mechanism.
  186. // Input:                     CoolGen_String reference
  187. // Output:                    CoolGen_String reference to new object
  188.  
  189. CoolGen_String::CoolGen_String (const CoolGen_String& s) {
  190.   this->growth_ratio = s.growth_ratio;    // Initialize growth ratio
  191.   this->length = s.length;        // Determine length of character string
  192.   this->str = s.str;            // Point to same string memory block
  193.   this->p = s.p;            // Point to same layout structure
  194.   this->p->ref_count++;            // Increment reference count
  195.   this->rgexp = NULL;            // No regular expression yet
  196. }
  197.  
  198.  
  199. // CoolGen_String(char*, size) -- Constructor to initialize object with a char*
  200. //                            and control initial allocation size
  201. // Input:                     char* pointer and size value
  202. // Output:                    CoolGen_String reference to new object
  203.  
  204. CoolGen_String::CoolGen_String (const char* c, long sz) {
  205.   this->length = strlen (c);        // Determine length of character string
  206.   this->p = new String_Layout;        // Allocate layout structure
  207.   if (this->length > sz) {        // If initial string is larger
  208.     this->str = new char[length+1];    // Allocate memory for string
  209.     this->p->size = length+1;        // Size of allocated block
  210.   }
  211.   else {
  212.     this->str = new char[sz+1];        // Allocate memory for string 
  213.     this->p->size = sz+1;        // Size of allocated block
  214.   }
  215.   this->p->ref_count = 1;        // One String object at the moment
  216.   this->p->start = this->str;        // Pointer to start of string
  217.   strcpy ((char *)this->str, c);    // Copy characters
  218.   this->rgexp = NULL;            // No regular expression yet
  219. }
  220.  
  221.  
  222. // CoolGen_String(CoolGen_String&, long) -- Constructor to initialize object to a
  223. //                                  CoolGen_String and control initial alloc size
  224. // Input:                           CoolGen_String reference and size value
  225. // Output:                          CoolGen_String reference to new object
  226.  
  227. CoolGen_String::CoolGen_String (const CoolGen_String& s, long sz) { 
  228.   this->length = s.length;        // Determine length of character string
  229.   this->p = new String_Layout;        // Allocate layout structure
  230.   if (this->length > sz) {        // If initial string is larger
  231.     this->str = new char[length+1];    // Allocate memory for string
  232.     this->p->size = length+1;        // Size of allocated block
  233.   }
  234.   else {
  235.     this->str = new char[sz+1];        // Allocate memory for string 
  236.     this->p->size = sz+1;        // Size of allocated block
  237.   }
  238.   this->p->ref_count = 1;        // One String object at the moment
  239.   this->p->start = this->str;        // Pointer to start of string
  240.   strcpy ((char *)this->str, s.str);    // Copy characters over
  241.   this->rgexp = NULL;            // No regular expression yet
  242. }
  243.  
  244.  
  245. // ~CoolGen_String() -- CoolGen_String object destructor frees up allocated memory and
  246. //                  decrements reference count if necessary
  247. // Input:           CoolGen_String object
  248. // Output:          None
  249.  
  250. CoolGen_String::~CoolGen_String () {            
  251.   if (this->p->ref_count == 1) {      // If not sharing mem with other String
  252.     delete this->str;              // then delete String object
  253.     delete this->p;              // Delete layout structure
  254.   } else 
  255.     this->p->ref_count--;        // Else decrement reference counter
  256.   delete this->rgexp;            // Delete regular expression object
  257. }
  258.  
  259.  
  260. // clear -- Flush the character string from the string object by setting
  261. //          the char* pointer to NULL and the length to zero.
  262. // Input:   this*
  263.     // Output:  None
  264.  
  265. void CoolGen_String::clear() {
  266.   this->length = 0;            // Set new string length
  267.   if (this->rgexp)            // If there is a Regexp object
  268.     this->rgexp->set_invalid();        // Invalidate compiled expression
  269.   if (this->p->ref_count == 1)        // If not sharing mem with other String
  270.     *(this->str) = NULL;        // Clear this String by using NULL
  271.   else {
  272.     this->str = NULL;            // Invalidate pointer
  273.     this->validate();            // Check for sharing memory and reset
  274.   }
  275. }
  276.  
  277.  
  278. // strcpy -- String copy of a single character to an CoolGen_String object
  279. // Input:    CoolGen_String reference and a character
  280. // Output:   CoolGen_String object containing a character string
  281.  
  282. CoolGen_String& strcpy (CoolGen_String& s, char c) {
  283.   s.length = 1;                // Character string length
  284.   s.validate(TRUE);            // Ensure enough memory and not shared
  285.   *(s.str) = c;                // Assign character
  286.   *(s.str+1) = END_OF_STRING;        // END_OF_STRING terminator for string
  287.   return s;                // Return CoolGen_String reference
  288. }  
  289.  
  290.  
  291. // strcpy -- String copy of a char* to a String object
  292. // Input:    CoolGen_String reference and a char* 
  293. // Output:   String object containing a character string
  294.  
  295. CoolGen_String& strcpy (CoolGen_String& s, const char *c) {
  296.   s.length = strlen (c);        // Determine length of character string
  297.   s.validate(TRUE);            // Ensure enough memory and not shared
  298.   strcpy(s.str, c);            // Copy into string
  299.   return s;                // Return CoolGen_String reference
  300. }
  301.  
  302.  
  303. // strcpy -- String copy of one String object to another. Note that the
  304. //           copy is delayed via the reference count mechanism until it
  305. //           is really needed.
  306. // Input:    Two CoolGen_String references
  307. // Output:   CoolGen_String object pointing to another CoolGen_String object
  308.  
  309. CoolGen_String& strcpy (CoolGen_String& s1, const CoolGen_String& s2) {
  310.   if (s1.p->ref_count > 1)        // If sharing memory with other string
  311.     s1.p->ref_count--;            // Decrement that reference count
  312.   else {                // Else must be some memory to free
  313.     delete s1.p;            // Free layout structure memory
  314.     if (s1.str != END_OF_STRING)        // If pointing to a memory block
  315.       delete s1.str;            // Free that up too
  316.   }
  317.   s1.length = s2.length;        // Determine length of character string
  318.   s1.str = s2.str;            // Point to same string memory block
  319.   s1.p = s2.p;                // Point to same layout structure
  320.   s1.p->ref_count++;            // Increment reference count
  321.   return s1;                // Return CoolGen_String reference
  322. }
  323.  
  324.  
  325. // strcat -- Concatenate a single character to a CoolGen_String object
  326. // Input:    CoolGen_String reference and a character
  327. // Output:   CoolGen_String object concatenated with character 
  328.  
  329. CoolGen_String& strcat (CoolGen_String& s, char c) {
  330.   s.length += 1;            // Determine length of new string
  331.   s.validate();                // Ensure enough memory and not shared
  332.   s.str[s.length-1] = c;        // Append new character
  333.   s.str[s.length] = END_OF_STRING;    // END_OF_STRING terminator
  334.   return s;                // Return String
  335. }
  336.  
  337.  
  338. // strcat -- Concatenate a String and a char*
  339. // Input:    CoolGen_String reference and a char*
  340. // Output    CoolGen_String object concatentated with character string
  341.  
  342. CoolGen_String& strcat (CoolGen_String& s, const char* c) {    
  343.   long old_len = s.length;        // Save length for efficiency hack
  344.   s.length = old_len + strlen (c);    // Determine length of new string
  345.   s.validate();                // Ensure enough memory and not shared
  346.   strcpy (s.str+old_len, c);        // Concatenate characters   
  347.   return s;                // Return String
  348. }
  349.  
  350.  
  351. // strncat -- Concatentate a String with "n" characters from char*
  352. // Input:     CoolGen_String reference, char*, number of characters
  353. // Output:    CoolGen_String object concatenedate with "n" characters
  354.  
  355. CoolGen_String& strncat (CoolGen_String& s, const char* c, int n) {
  356. #if ERROR_CHECKING
  357.   if (n < 0) {                // If invalid length
  358.     printf ("CoolGen_String::strncat(): Negative length %d.\n", n);
  359.     exit (1);
  360.   }
  361. #endif
  362.   long old_len = s.length;        // Save length for efficiency hack
  363.   s.length = old_len + n;        // Determine length of new string
  364.   s.validate();                // Ensure enough memory and not shared
  365.   strncpy (s.str+old_len, c, size_t(n));    // Concatenate characters   
  366.   return s;                // Return String
  367. }
  368.  
  369.  
  370. // strcat -- Concatenate two CoolGen_String objects
  371. // Input:    Two CoolGen_String references
  372. // Output:   CoolGen_String object concatenated with CoolGen_String object
  373.  
  374. CoolGen_String& strcat (CoolGen_String& s1, const CoolGen_String& s2) {
  375.   long old_len = s1.length;        // Save length for efficiency hack
  376.   s1.length = old_len + s2.length;    // Determine length of new string
  377.   s1.validate();            // Ensure enough memory and not shared
  378.   strcpy (s1.str+old_len, s2.str);    // Copy remaining characters 
  379.   return s1;                // Return String
  380. }
  381.  
  382.  
  383. // strncat -- Concatentate a String with "n" characters from a String
  384. // Input:     Two CoolGen_String references and number of characters
  385. // Output:    CoolGen_String object concatenedate with "n" characters
  386.  
  387. CoolGen_String& strncat (CoolGen_String& s1, const CoolGen_String& s2, int n) {
  388. #if ERROR_CHECKING
  389.   if (n < 0) {                // If invalid length
  390.     printf ("CoolGen_String::strncat(): Negative length %d.\n", n);
  391.     exit (1);
  392.   }
  393. #endif
  394.   long old_len = s1.length;        // Save length for efficiency hack
  395.   s1.length = old_len + n;        // Determine length of new string
  396.   s1.validate();            // Ensure enough memory and not shared
  397.   strncpy (s1.str+old_len, s2.str, size_t(n));    // Copy remaining characters 
  398.   return s1;                // Return String
  399. }
  400.  
  401.  
  402. // compile -- Compile a regular expression ready for pattern matching. If no
  403. //            regexp object in string, create one
  404. // Input:     Regular expression to compile
  405. // Output:    None
  406.  
  407. void CoolGen_String::compile (const char* s) {
  408.   if (this->rgexp == NULL)             // If no regexp object 
  409.     this->rgexp = new CoolRegexp;            // Allocate storage for regexp
  410.   this->rgexp->compile (s);            // Compile regular expression
  411.   this->rgexp_index = 0;            // Reset search index position
  412. }
  413.  
  414.  
  415. // find -- Search the string for the previously compiled regular expression
  416. // Input:  None
  417. // Output: Boolean TRUE/FALSE
  418.  
  419. Boolean CoolGen_String::find () {
  420. #if ERROR_CHECKING
  421.   if (this->rgexp == NULL || !this->rgexp->is_valid()) // Valid regexp?
  422.     this->find_error ();                // Raise exception
  423. #endif
  424.   this->rgexp_index += this->rgexp->end ();    // Use index from last search
  425.   if (this->rgexp_index >= this->length)    // If at end of search
  426.     return FALSE;                // Indicate failure
  427.   Boolean result = this->rgexp->find (this->str + this->rgexp_index);
  428.   return result;                // Return match result
  429. }
  430.  
  431.  
  432. // reverse -- Reverse the order of the characters in CoolGen_String object
  433. // Input:     CoolGen_String object
  434. // Output:    CoolGen_String object with character order reverse
  435.  
  436. void CoolGen_String::reverse () {
  437.   char c;
  438.   for (long i = 0, j = this->length-1;        // Counting from front and rear
  439.        i < this->length / 2; i++, j--) {    // until we reach the middle
  440.     c = this->str[i];                // Save front character
  441.     this->str[i] = this->str[j];        // Switch with rear character
  442.     this->str[j] = c;                // Copy new rear character
  443.   }
  444. }
  445.  
  446.  
  447. // resize -- Adjust the memory size of a string to accomodate some size
  448. // Input:    CoolGen_String object
  449. // Output:   None
  450.  
  451. void CoolGen_String::resize (long sz) {
  452. #if ERROR_CHECKING
  453.   if (sz < 0) {                // If invalid resize
  454.     printf ("CoolGen_String::resize(): Negative resize %d.\n", sz);
  455.     exit (1);
  456.   }
  457. #endif
  458.   int shared_memory = FALSE;        // If TRUE, memory shared
  459.   char* temp = this->str;        // Save pointer to existing string
  460.   if (this->p->ref_count > 1) {            // If sharing memory with other String
  461.     this->update_ref_count();        // Adjust and update
  462.     shared_memory = TRUE;        // Set flag for later use
  463.   }
  464.   this->str = new char[sz+1];        // Allocate memory for desired size
  465.   this->p->start = str;            // Pointer to start of string
  466.   this->p->size = sz+1;            // Save size of allocated memory
  467.   if (temp != NULL)            // If original string had data
  468.     strcpy ((char *)this->str, temp);    // Copy original string back
  469.   if (shared_memory == FALSE)        // If did not share memory
  470.     delete temp;            // Deallocate memory
  471. }
  472.  
  473.  
  474. // operator<< -- Overload output operator for CoolGen_String objects
  475. // Input:        CoolGen_String object
  476. // Output:       Formatted output and stream descriptor
  477.  
  478. ostream& operator<< (ostream& os, const CoolGen_String& s) {
  479.   return os << s.str;                // Output char* and newline
  480. }
  481.  
  482.  
  483. // strtol -- Returns as a long integer the value represented by the
  484. //           string pointer to by s, scanning upto the first character
  485. //           that is inconsistent with the base. Leading white space is
  486. //           ignored.
  487. // Input:    Reference to CoolGen_String object
  488. //           Radix of number
  489. // Output:   Long integer representing value contained in the String
  490.  
  491. long strtol (const CoolGen_String& s, char** ptr, int radix) {
  492.   return (strtol ((char *)s.str, ptr, radix)); 
  493. }    
  494.  
  495.  
  496. // atol -- Equivalent to: strtol (str, (char**)END_OF_STRING, 10)
  497. // Input:  Reference to CoolGen_String object
  498. // Output: Long integer representing value contained in the String
  499.  
  500. long atol (const CoolGen_String& s) {        
  501.   return (strtol ((char *)s.str, (char **) END_OF_STRING, int(10)));
  502. }
  503.  
  504.  
  505. // atoi -- Equivalent to: (int)strtol (str, (char**)END_OF_STRING, 10)
  506. // Input:  Reference to CoolGen_String object
  507. // Output: Integer representing value contained in the String
  508.  
  509. int atoi (const CoolGen_String& s) {        
  510.   return int(strtol ((char *)s.str, (char **) END_OF_STRING, int(10)));    
  511. }
  512.  
  513.  
  514. // strtod -- Returns as a double-precision floating-point number the
  515. //           value represented by a CoolGen_String object. Characters are
  516. //           scanned upto the first unrecognized character.
  517. // Input:    Reference to CoolGen_String object
  518. // Output:   Double representing value contained in String
  519.  
  520. double strtod (const CoolGen_String& s, char** ptr) {        
  521.   return (strtod ((char *)s.str, ptr));
  522. }
  523.  
  524.  
  525. // trim -- Removes any occurrence of the character(s) in "c" from "s"
  526. // Input:  CoolGen_String reference, character string
  527. // Output: Modified String "s" object
  528.  
  529. CoolGen_String& trim (CoolGen_String& sr, const char* rem) {
  530.   sr.validate();            // Ensure not shared
  531.   char* s = sr.str;
  532.   char* result = sr.str;
  533.   long len = 0;
  534.   register char c;
  535.   while ((c=*s++) != END_OF_STRING) {
  536.     register const char* r = rem;
  537.     register char t;
  538.     while ((t=*r++) != END_OF_STRING && t != c); // Scan for match
  539.     if (t == END_OF_STRING)             // If no match found
  540.       *result++ = c, len++;
  541.   }
  542.   *result = END_OF_STRING;            // NULL terminate string
  543.   sr.length = len;
  544.   return sr;                    // Return string
  545. }
  546.  
  547.  
  548. // left_trim -- Removes any occurrence of the character(s) in "c" from
  549. //              "s" that appear as a prefix to the string. The first
  550. //              non-matching character encountered terminates the remove
  551. //              operation and the rest of the string is copied intact.
  552. // Input:       CoolGen_String reference, character string
  553. // Output:      Modified String "s" object
  554.  
  555. CoolGen_String& left_trim (CoolGen_String& sr, const char* rem) {
  556.   sr.validate();            // Ensure not shared
  557.   char* result = sr.str;
  558.   char* s = sr.str;
  559.   long len = 0;
  560.   register char c;
  561.   for (; (c=*s) != END_OF_STRING; s++) {
  562.     register const char* r = rem;
  563.     register char t;
  564.     while ((t=*r++) != END_OF_STRING && t != c); // Scan for match
  565.     if (t == END_OF_STRING)             // If no match found
  566.       break;
  567.   }
  568.   if (s != result)                  // when characters trimed
  569.     while ((*result++ = *s++) != END_OF_STRING) len++; // shift string down
  570.   sr.length = len;
  571.   return sr;                // Return string reference
  572. }
  573.  
  574.  
  575. // right_trim -- Removes any occurrence of the character(s) in "c" from
  576. //               "s" that appear as a suffix to the string. The first
  577. //               non-matching character encountered terminates the remove
  578. //               operation and the rest of the string is copied intact.
  579. // Input:        CoolGen_String reference, character string
  580. // Output:       Modified String "s" object
  581.  
  582. CoolGen_String& right_trim (CoolGen_String& sr, const char* rem) {    
  583.   sr.validate();            // Ensure not shared
  584.   char* str = sr.str;
  585.   char* s = str + strlen(str) - 1;        // last character of string
  586.   for (; s >= str; s--) {
  587.     register const char* r = rem;
  588.     register char t;
  589.     register char c = *s;
  590.     while ((t=*r++) != END_OF_STRING && t != c); // Scan for match
  591.     if (t == END_OF_STRING)             // If no match found
  592.       break;
  593.   }
  594.   *(s+1) = END_OF_STRING;
  595.   sr.length = s - str;
  596.   return sr;                // Return String reference
  597. }
  598.  
  599.  
  600. // upcase -- Convert all alphabetical characters to uppercase
  601. // Input:    CoolGen_String reference
  602. // Output:   Updated string
  603.  
  604. CoolGen_String& upcase (CoolGen_String& s) {    // Convert entire string to upper case
  605.   s.validate();                // Ensure not shared
  606.   c_upcase(s.str);
  607.   return s;                // Return reference to modified string
  608. }
  609.  
  610.  
  611. // downcase -- Convert all alphabetical characters to lowercase
  612. // Input:      CoolGen_String reference
  613. // Output:     Updated string
  614.  
  615. CoolGen_String& downcase (CoolGen_String& s) {    // Convert entire string to lower case
  616.   s.validate();            // Ensure not shared
  617.   c_downcase(s.str);
  618.   return s;            // Return reference to modified string
  619. }
  620.  
  621. // capitalize -- Capitalize all words in a String. A word is define as
  622. //               a sequence of characters separated by white space
  623. // Input:        CoolGen_String reference
  624. // Output:       Updated string
  625.  
  626. CoolGen_String& capitalize (CoolGen_String& s) {    
  627.   s.validate();            // Ensure not shared
  628.   c_capitalize(s.str);
  629.   return s;            // Return reference to modified string
  630. }
  631.  
  632.  
  633. // insert -- Insert a char* at the position specified by start.
  634. // Input  -- A char* to be inserted and a long index.          
  635. // Output -- A Boolean, true if insertion took place, false if error.
  636.  
  637. Boolean CoolGen_String::insert (const char* ins, long start) {
  638.   if (start<0 || start>this->length) return(FALSE);  // Boundary check
  639.   long len=strlen(ins);                 // length of char*
  640.   this->length += len;              // Determine length of new string
  641.   this->validate();            // Ensure not shared and enough memory
  642.   register char* ptr = this->str;
  643.   register char* st = ptr + start;
  644.   register char* end = ptr + this->length;
  645.   for (ptr = end - len; ptr >= st;)        // Make space for ins
  646.     *end-- = *ptr--;
  647.   for (end = st+len; st < end; *st++ = *ins++);    // Insert ins into that
  648.   return(TRUE);                // Insert worked
  649. }
  650.  
  651.  
  652. // remove -- Removes everything between the start and end indexes of string
  653. //           The character at start is removed and all characters up to but 
  654. //           not including the character at end.
  655. // Input  -- A start and end index into the string.
  656. // Output -- A Boolean, true if remove worked, false if error.
  657.  
  658. Boolean CoolGen_String::remove (long start, long end) {
  659. #if ERROR_CHECKING
  660.   if (start < 0 || start > this->length || end < 0
  661.       || end > this->length || end <= start) {
  662.     printf ("CoolGen_String::remove(): Start %d and/or end %d index invalid.\n",
  663.         start, end);
  664.     exit (1);
  665.   }
  666. #endif
  667.   this->validate();                 // Ensure not shared
  668.   this->length -= (end-start);             // New (shorter) length
  669.   for(; this->str[start]=this->str[end]; start++) end++; // Remove everything
  670.   return(TRUE);                              // Remove worked
  671. }
  672.  
  673.  
  674. // replace -- Removes everything between start and end as in remove(), and
  675. //            inserts the char* argument into the place of what was removed.
  676. // Input   -- A start and end for remove and a char*, c, to insert.
  677. // Output  -- A Boolean, true if replace worked, false if error.
  678.  
  679. Boolean CoolGen_String::replace (const char* c, long start, long end) {
  680. #if ERROR_CHECKING
  681.   if (start < 0 || start > this->length || end < 0            // Boundary check
  682.       || end > this->length || end <= start) {
  683.     printf ("CoolGen_String::replace(): Start %d and/or end %d index invalid.\n",
  684.         start, end);
  685.     exit (1);
  686.   }
  687. #endif
  688.   long len=strlen(c);                   // length of c
  689.   long delta = len - end + start;    // find overall change in length
  690.   this->length += delta;        // set new length
  691.   this->validate();                // Ensure not shared and enough memory
  692.   long ind;
  693.   if (delta > 0) {                      // If replacement is bigger
  694.     for (ind=this->length; start+len<=ind; ind--) // than chacters replaced
  695.       this->str[ind] = this->str[ind-delta];
  696.   }
  697.   else if (delta < 0) {          // Replacement is shorter
  698.     char* st = this->str + start + len;
  699.     char* ptr = this->str + end;
  700.     char* end = this->str + this->length;
  701.     while (st<=end) *st++ = *ptr++;
  702.   }
  703.   { char* ptr = this->str+start;
  704.     char ch;
  705.     while ((ch = *c++) != END_OF_STRING) // replace characters
  706.       *ptr++ = ch;
  707.   }
  708.   return(TRUE);
  709. }
  710.  
  711.  
  712. // yank   -- Removes everything between start and end, copies it into a 
  713. //           a string and returns that string.
  714. // Input  -- A reference to a CoolGen_String. A start and end for the remove.
  715. // Output -- none.  the CoolGen_String passed in gets set.
  716.  
  717. void CoolGen_String::yank (CoolGen_String& s, long start, long end) {
  718. #if ERROR_CHECKING
  719.   if (start < 0 || start > this->length || end < 0    // Boundary check
  720.       || end > this->length || end <= start) {
  721.     printf ("CoolGen_String::yank(): Start %d and/or end %d index invalid.\n",
  722.         start,end);
  723.     exit (1);
  724.   }
  725. #endif
  726.   this->validate();            // Ensure not shared
  727.   long len = end - start;
  728.   strncpy(s, this->str+start, len);    // Copy stuff to yank into s
  729.   this->length -= len;            // set new length
  730.   for(; this->str[start]=this->str[end]; start++) end++;  // Do the remove
  731. }
  732.  
  733.  
  734. // sub_string -- Returns a new string initialized to what is between the
  735. //               start and end indexes.
  736. // Input      -- A CoolGen_String reference.  Two longs, a start and an end
  737. // Output     -- none.  Sets the given CoolGen_String.
  738.  
  739. void CoolGen_String::sub_string (CoolGen_String& s, long start, long end) {
  740. #if ERROR_CHECKING
  741.   if (start < 0 || start > this->length || end < 0    // Boundary check
  742.       || end > this->length || end <= start) {
  743.     printf ("CoolGen_String::sub_string(): Start %d and/or end %d index invalid.\n",
  744.         start, end);
  745.     exit (1);
  746.   }
  747. #endif
  748.   strncpy(s, this->str+start, end - start);    // Copy substring into s
  749. }
  750.  
  751.  
  752. // strncpy -- Returns s, with the first length characters of source copied
  753. //            into it.  The old value of s is lost.
  754. // Input   -- A reference to a CoolGen_String s, a char* source, and a long length.
  755. // Output  -- The modified CoolGen_String s.
  756.  
  757. CoolGen_String& strncpy(CoolGen_String& s, const char* source, long length) {
  758. #if ERROR_CHECKING  
  759.   if (length < 0) {            // Boundary check
  760.     printf ("CoolGen_String::strncpy(): Negative length %d.\n", length);
  761.     exit (1);
  762.   }
  763. #endif
  764.   s.length = length;            // Set new string length
  765.   s.validate(TRUE);                // Ensure not shared and enough memory
  766.   char* p = s.str;
  767.   while (length-- > 0)            // Copy source into string
  768.     *p++ = *source++;
  769.   *p = END_OF_STRING;            // set the end byte
  770.   return s;
  771. }
  772.  
  773.  
  774. // bracket_error -- Raise exception for operator[]
  775. // Input:           Index
  776. // Output:          None
  777.  
  778. void CoolGen_String::bracket_error (long n) {
  779.   printf ("CoolGen_String::operator[](): Index %d out of range.\n", n);
  780.   exit (1);
  781. }
  782.  
  783.  
  784. // ratio_error -- Raise exception for set_growth_ratio
  785. // Input:         Ratio
  786. // Output:        None
  787.  
  788. void CoolGen_String::ratio_error (float r) {
  789.   printf ("CoolGen_String::set_growth_ratio(): Negative growth ratio %f.\n", r);
  790.   exit (1);
  791. }
  792.  
  793.  
  794. // size_error -- Raise exception for set_alloc_size
  795. // Input:        Growth size
  796. // Output:       None
  797.  
  798. void CoolGen_String::size_error (int n) {
  799.   printf ("CoolGen_String::set_alloc_size(): Negative growth size %d.\n", n);
  800.   exit (1);
  801. }
  802.  
  803.  
  804. // find_error -- Raise exception for find()
  805. // Input:        None
  806. // Output:       None
  807.  
  808. void CoolGen_String::find_error () {
  809.   printf ("CoolGen_String::find(): Invalid regular expression.\n");
  810.   exit (1);
  811. }
  812.